﻿using System;
using System.Collections.Generic;
using System.Linq;
using ControleRepresentante.Logic.Models;
using Attribute = ControleRepresentante.Logic.Models.Attribute;

namespace ControleRepresentante.Logic
{
    public interface IIndexColumnsProvider
    {
        IndexColumn RegisterColumn(string description, Guid id, bool isMandatory = false);
        IndexColumn RegisterColumn(Attribute attribute);
        void SetDefaultColumns(params IndexColumn[] indexColumns);
        IEnumerable<IndexColumn> GetIndexColumns();
        IndexColumn this[Guid id] { get; }
        IndexColumn this[Attribute attribute] { get; }
        IEnumerable<IndexColumn> GetAllIndexColumns();
    }

    public abstract class IndexColumn
    {
        public string Description { get; private set; }
        public bool IsMandatory { get; private set; }

        protected IndexColumn(string description, bool isMandatory)
        {
            Description = description;
            IsMandatory = isMandatory;
        }
    }

    public class BuiltInIndexColumn : IndexColumn
    {
        public BuiltInIndexColumn(string description, Guid id, bool isMandatory)
            : base(description, isMandatory)
        {
            Id = id;
        }

        public Guid Id { get; set; }
    }

    public class AttributeIndexColumn : IndexColumn
    {
        public AttributeIndexColumn(Attribute attribute)
            : base(attribute.Name, false)
        {
            Attribute = attribute;
        }

        public Attribute Attribute { get; private set; }
    }

    public class IndexColumnsProvider : IIndexColumnsProvider
    {
        private readonly Area? m_Area;
        private readonly User m_User;
        private readonly List<AttributeIndexColumn> m_AttributeIndexColumns;
        private readonly List<BuiltInIndexColumn> m_BuiltInIndexColumns;
        private IEnumerable<IndexColumn> m_Default;

        public IndexColumnsProvider(Area? area, User user)
        {
            m_Area = area;
            m_User = user;
            m_AttributeIndexColumns = new List<AttributeIndexColumn>();
            m_BuiltInIndexColumns = new List<BuiltInIndexColumn>();
            m_Default = new IndexColumn[0];
        }

        public IndexColumn RegisterColumn(string description, Guid id, bool isMandatory = false)
        {
            BuiltInIndexColumn builtInIndexColumn = new BuiltInIndexColumn(description, id, isMandatory);
            m_BuiltInIndexColumns.Add(builtInIndexColumn);
            return builtInIndexColumn;
        }

        public IndexColumn RegisterColumn(Attribute attribute)
        {
            AttributeIndexColumn attributeIndexColumn = new AttributeIndexColumn(attribute);
            m_AttributeIndexColumns.Add(attributeIndexColumn);
            return attributeIndexColumn;
        }

        public void SetDefaultColumns(params IndexColumn[] indexColumns)
        {
            m_Default = indexColumns;
        }

        public IEnumerable<IndexColumn> GetIndexColumns()
        {
            IndexColumnsPreference indexColumnsPreference = m_User.IndexColumnsPreferences.FirstOrDefault(x => x.Area == m_Area);
            if (indexColumnsPreference == null || (!indexColumnsPreference.BuiltInIndexColumnPreferences.Any() && !indexColumnsPreference.AttributeIndexColumnPreferences.Any()))
            {
                return m_Default;
            }
            List<IndexColumn> result = new List<IndexColumn>();
            foreach (AttributeIndexColumn attributeIndexColumn in m_AttributeIndexColumns)
            {
                AttributeIndexColumnPreference attributeIndexColumnPreference = 
                    indexColumnsPreference.AttributeIndexColumnPreferences.FirstOrDefault(x => x.Attribute.Id == attributeIndexColumn.Attribute.Id);
                if (attributeIndexColumnPreference != null)
                {
                    result.Add(attributeIndexColumn);
                }
            }
            foreach (BuiltInIndexColumn builtInIndexColumn in m_BuiltInIndexColumns)
            {
                if (builtInIndexColumn.IsMandatory)
                {
                    result.Add(builtInIndexColumn);
                }
                else
                {
                    BuiltInIndexColumnPreference builtInIndexColumnPreference =
                        indexColumnsPreference.BuiltInIndexColumnPreferences.FirstOrDefault(x => x.ColumnId == builtInIndexColumn.Id);
                    if (builtInIndexColumnPreference != null)
                    {
                        result.Add(builtInIndexColumn);
                    }
                }
            }
            return result;
        }

        IndexColumn IIndexColumnsProvider.this[Guid id]
        {
            get { return m_BuiltInIndexColumns.FirstOrDefault(x => x.Id == id); }
        }

        IndexColumn IIndexColumnsProvider.this[Attribute attribute]
        {
            get { return m_AttributeIndexColumns.FirstOrDefault(x => x.Attribute.Id == attribute.Id); }
        }

        public IEnumerable<IndexColumn> GetAllIndexColumns()
        {
            return m_AttributeIndexColumns.Cast<IndexColumn>().Union(m_BuiltInIndexColumns);
        }
    }
}
